package dev.ece.suit.hexmap.terrain;

import java.util.List;

import dev.ece.suit.hexmap.MapCell;
import dev.ece.suit.hexmap.MapCellCreator;
import dev.ece.suit.hexmap.MapCrevice;
import dev.ece.suit.hexmap.MapCreviceCreator;
import dev.ece.suit.hexmap.TerrainModelCreator;
import dev.ece.util.lib.Vector2f;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.NormalUtils;

public class SimpleMapCreviceCreator implements MapCreviceCreator {

	private int count;
	
	private int size;
	
	private TerrainModelCreator terrainModelCreator;
	
	public SimpleMapCreviceCreator(TerrainModelCreator terrainModelCreator) {
		this.terrainModelCreator = terrainModelCreator;
		this.count = computeCount();
		this.size = computeSize();
	}
	
	@Override
	public MapCrevice create(int index, MapCell left, MapCell right, int leftIndex) {
		int first = count() * index;
		int rightIndex = leftIndex - 3;
		int vrows = rows() + 1;
		
		MapCell[] cells = new MapCell[] {left, right};
		Vector3f[][] vertice = new Vector3f[vrows][];
		Vector3f[][] normals = new Vector3f[vrows][];
		Vector2f[][] uv = new Vector2f[vrows][];
		float[][] alpha = new float[vrows][];
		
		fillFirstRowData(right, rightIndex, vertice, normals, uv, alpha);
		fillLastRowData(left, leftIndex, vertice, normals, uv, alpha);
		fillMiddleRowData(vertice, normals, uv, alpha);
		fillNormalsData(vertice, normals);
		
		MapCrevice result = new MapCrevice(cells, vertice, normals, uv, alpha, first);
		left.getNeighbors()[leftIndex] = result;
		right.getNeighbors()[rightIndex] = result;
		return result;
	}
	
	@Override
	public void fillData(MapCrevice crevice, List<Vector3f> vertice, List<Vector2f> uv, List<Vector3f> normals,
			List<Float> alpha) {
		int len = 0;
		int prow = 0;
		int ncol = 0;
		for(int i=1; i<crevice.getVertice().length; i++) {
			prow = i-1;
			len = crevice.getVertice()[i].length - 1;
			for(int j=0; j<len; j++) {
				ncol = j + 1;
				vertice.add(crevice.getVertice()[prow][j]);
				vertice.add(crevice.getVertice()[i][j]);
				vertice.add(crevice.getVertice()[prow][ncol]);
				
				uv.add(crevice.getUv()[prow][j]);
				uv.add(crevice.getUv()[i][j]);
				uv.add(crevice.getUv()[prow][ncol]);
				
				normals.add(crevice.getNormals()[prow][j]);
				normals.add(crevice.getNormals()[i][j]);
				normals.add(crevice.getNormals()[prow][ncol]);
				
				alpha.add(crevice.getAlpha()[prow][j]);
				alpha.add(crevice.getAlpha()[i][j]);
				alpha.add(crevice.getAlpha()[prow][ncol]);
				
				vertice.add(crevice.getVertice()[prow][ncol]);
				vertice.add(crevice.getVertice()[i][j]);
				vertice.add(crevice.getVertice()[i][ncol]);
				
				uv.add(crevice.getUv()[prow][ncol]);
				uv.add(crevice.getUv()[i][j]);
				uv.add(crevice.getUv()[i][ncol]);
				
				normals.add(crevice.getNormals()[prow][ncol]);
				normals.add(crevice.getNormals()[i][j]);
				normals.add(crevice.getNormals()[i][ncol]);
				
				alpha.add(crevice.getAlpha()[prow][ncol]);
				alpha.add(crevice.getAlpha()[i][j]);
				alpha.add(crevice.getAlpha()[i][ncol]);
			}
		}
	}

	protected void fillMiddleRowData(Vector3f[][] vertice, Vector3f[][] normals, Vector2f[][] uv, float[][] alpha) {
		float tAlpha = 0;
		for(int i=1; i<rows(); i++) {
			vertice[i] = new Vector3f[size()];
			uv[i] = new Vector2f[size()];
			alpha[i] = new float[size()];
			tAlpha = 1f / rows() * i;
			for(int j=0; j<size(); j++) {
				vertice[i][j] = new Vector3f().interpolate(vertice[0][j], vertice[rows()][j], tAlpha);
				uv[i][j] = new Vector2f().interpolate(uv[0][j], uv[rows()][j], tAlpha);
				alpha[i][j] = tAlpha;
			}
		}
	}
	
	protected void fillNormalsData(Vector3f[][] vertice, Vector3f[][] normals) {
		Vector3f normal = null;
		int len = getTerrainModelCreator().getMapCellCreator().getCircles();
		int prow = 0;
		int ncol = 0;
		for(int i=1; i<vertice.length; i++) {
			if(normals[i] == null) {
				normals[i] = new Vector3f[size()];
			}
			prow = i - 1;
			for(int j=0; j<len; j++) {
				ncol = j + 1;
				normal = NormalUtils.buildNormal(
						vertice[prow][j], 
						vertice[i][j], 
						vertice[prow][ncol], null);
				normals[prow][j] = MapCellCreator.addNormal(normals[prow][j], normal);
				normals[i][j] = MapCellCreator.createNormal(normals[i][j], normal);
				normals[prow][ncol] = MapCellCreator.addNormal(normals[prow][ncol], normal);
				
				normal = NormalUtils.buildNormal(
						vertice[prow][ncol], 
						vertice[i][j], 
						vertice[i][ncol], null);
				normals[prow][ncol] = MapCellCreator.addNormal(normals[prow][ncol], normal);
				normals[i][j] = MapCellCreator.addNormal(normals[i][j], normal);
				normals[i][ncol] = MapCellCreator.createNormal(normals[i][ncol], normal);
			}
		}
	}
	
	protected void fillLastRowData(MapCell left, int leftIndex, Vector3f[][] vertice, Vector3f[][] normals, Vector2f[][] uv, float[][] alpha) {
		vertice[rows()] = new Vector3f[size()];
		normals[rows()] = new Vector3f[size()];
		uv[rows()] = new Vector2f[size()];
		alpha[rows()] = new float[size()];
		int index = 0;
		int len = left.getVertice()[0].length;
		int startIndex = getTerrainModelCreator().getMapCellCreator().getCircles() * (leftIndex + 1);
		int outIndex = getTerrainModelCreator().getMapCellCreator().getCircles() - 1;
		for(int i=0; i<size(); i++) {
			index = startIndex % len;
			vertice[rows()][i] = left.getVertice()[outIndex][index];
			normals[rows()][i] = left.getNormals()[outIndex][index];
			uv[rows()][i] = left.getUv()[outIndex][index];
			alpha[rows()][i] = 1f;
			startIndex --;
		}
	}
	
	protected void fillFirstRowData(MapCell right, int rightIndex, Vector3f[][] vertice, Vector3f[][] normals, Vector2f[][] uv, float[][] alpha) {
		vertice[0] = new Vector3f[size()];
		normals[0] = new Vector3f[size()];
		uv[0] = new Vector2f[size()];
		alpha[0] = new float[size()];
		int outIndex = getTerrainModelCreator().getMapCellCreator().getCircles() - 1;
		int startIndex = getTerrainModelCreator().getMapCellCreator().getCircles() * rightIndex;
		for(int i=0; i<size(); i++) {
			vertice[0][i] = right.getVertice()[outIndex][startIndex];
			normals[0][i] = right.getNormals()[outIndex][startIndex];
			uv[0][i] = right.getUv()[outIndex][startIndex];
			alpha[0][i] = 0f;
			startIndex ++;
		}
	}
	
	protected int computeSize() {
		return getTerrainModelCreator().getMapCellCreator().getCircles() + 1;
	}

	protected int computeCount() {
		//纵向分6份
		return getTerrainModelCreator().getMapCellCreator().getCircles() * rows() * 2 * 3;
	}
	
	public TerrainModelCreator getTerrainModelCreator() {
		return terrainModelCreator;
	}

	@Override
	public int rows() {
		return 6;
	}

	@Override
	public int count() {
		return count;
	}

	@Override
	public int size() {
		return size;
	}
	
}
